import sys 
sys.path.append('..')
import numpy as np

from common.layers import Embedding
from negative_sampling_layer import NegativeSamplingLoss

class CBOW:
    """CBOW模型（也就是给出两边的若干单词，预测中间出现的单词"""
    def __init__(self,vocab_size,hidden_size,window_size,corpus):
        V,H = vocab_size,hidden_size

        # 初始化权重
        W_in = 0.01*np.random.randn(V,H).astype('f')
        W_out = 0.01*np.random.randn(V,H).astype('f')

        # 生成层
        self.in_layers = []
        for i in range(2*window_size):
            layer = Embedding(W_in)
            self.in_layers.append(layer)
        self.ns_loss = NegativeSamplingLoss(W_out,corpus,power=0.75,sample_size=5)

        # 将所有的权重和梯度整理到列表中
        layers = self.in_layers + [self.ns_loss]
        self.params,self.grads = [],[]
        for layer in layers:
            self.params += layer.params 
            self.grads += layer.grads  

        # 将单词的分布式表示设置成成员变量
        self.word_vecs = W_in

    def forward(self,contexts,target):
        h = 0
        for i, layer in enumerate(self.in_layers):
            h += layer.forward(contexts[:,i])
        h *= 1/len(self.in_layers)
        loss = self.ns_loss.forward(h,target)
        return loss   
    
    def backward(self,dout=1):
        dout = self.ns_loss.backward(dout)
        dout *= 1/len(self.in_layers)
        for layer in self.in_layers:
            layer.backward(dout)
        return None 